//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#include "sagittarius/core/SagittariusCore.h"
#include "sagittarius/parser/parser.h"
#include "sagittarius/io/io.h"
#include <string.h>
#include <malloc.h>

#define PRINT_EXPANSIONS

#ifdef PRINT_EXPANSIONS
//     #include "sagittarius/io/io.h"
    #define USING_EXPANSION(x) SG_WRITE(1, x);
#else
    #define USING_EXPANSION(x)
#endif

/// parserErr
void parserErr(parser* p, const char* str, ...) {
    va_list v;
    va_start(v, str);
    vfprintf(stderr, str, v);
    va_end(v);
    fflush(stderr);
    //AN(0);
}

void vparserErr(parser* p, const char* str, va_list v) {
    vfprintf(stderr, str, v);
}

/// parserInitBuf
void parserInitBuf(parser* p, constLexBuf buf) {
    p->intr = 0;
    p->s = malloc(sizeof(scanner_t));
    initScanner(p->s, buf);
}

/// parserFinalize
void parserFinalize(parser* p) {
    finalizeScanner(p->s);
    free(p->s);
}

/// parserMatch
int parserMatch(parser* p, uint32 t) {
    if(scannerTok(p->s).tok == t) {
        scannerAdvance(p->s);
        return 1;
    } else
        return 0;
}

/// discardNewline
int discardNewline(parser* p) {
    while(scannerTok(p->s).tok == TOKEN_nl)
        scannerAdvance(p->s);
    return 0;
}

/// parserMatch
int parserMatchIdC(parser* p, const char* str) {
    //SG_WRITE(2, "Match \"");
    //LX_WRITE_BUFL(2, p->s->tok.pos, p->s->tok.l);
    if(scannerTok(p->s).tok == TOKEN_id) {
        size_t l;
        LexBuf b=sg_lex_str2buf(str);
        /*SG_WRITE(2, "\" vs \"");
        LX_WRITE_BUF(2, b);
        SG_WRITE(2, "\"\n");*/
        l=LX_BUFFER_LEN(b)-1;
        if(l == scannerTok(p->s).l) {
            if(sg_lex_bufeql(scannerTok(p->s).pos, b, l)) {
                LX_FREE_BUFFER(b);
                scannerAdvance(p->s);
                return 1;
            }
        }
        LX_FREE_BUFFER(b);
        return 0;
    } else {
        return 0;
    }
}

/// parseSource
sourceFrag* parseSource(parser* p) {
    parserExp* b=NULL;
    sourceFrag* sf=createSourceFrag();
    
    while(!scannerEOI(p->s) || p->intr) {
        discardNewline(p);
        SG_WRITE(2, "parseSource Token:\n");
        dumpToken(scannerTok(p->s));
        //off-side rule switch
        if(parserMatchIdC(p, "offside")) {
            if(parserMatchIdC(p, "both")) {
                //tolerate both methods
                p->s->tol_offside = 1;
                p->s->tol_dlim_blocks = 1;
            }else if(parserMatchIdC(p, "on")) {
                //exclusive: off-side only
                p->s->tol_offside = 1;
                p->s->tol_dlim_blocks = 0;
            }else if(parserMatchIdC(p, "off")) {
                //exclusive: phrase-based grouping
                p->s->tol_offside = 0;
                p->s->tol_dlim_blocks = 1;
            } else {
                parserErr(p, "Statement \"offside\" may only be followed by \"on\", \"off\", or \"both\"\n");
                continue;
            }
        }
        //function def
        if(parserMatchIdC(p, "def")) {
            functionDef* f=parseFunDef(p);
            if(f)
                sfPushFDef(sf, f);
        //} else if(parserMatchIdC(p, "import")) {
            //parserExp* q = parseImportStmt(p);
            //if(q)
                //sfPushImport(sf, q);
        } else {
            parserExp* e;
            e = parseExpr(p);
            if(e) {
                if(b) {
                    b->b = createParserExp();
                    b->ownb = 1;
                    b = b->b;
                } else {
                    sf->b = createParserExp();
                    b = sf->b;
                }
                b->type = PAST_NODE_TYPE_BBLOCK_LINK;
                b->a = e;
                b->owna = 1;
            } else
                parserErr(p, "Error parsing expression\n");
        }
        discardNewline(p);
    }
    return sf;
}

/// parseImportChain
parserExp* parseImportChain(parser* p) {
    SG_WRITE(2, "parseLval\n");
    parserExp* l;
    //id
    if(scannerTok(p->s).tok != TOKEN_id) {
        parserErr(p, "--Expected lvalue symbol--\n");
        return NULL;
    }
    l = createParserExp();
    l->type = PAST_NODE_TYPE_SYMBOL;
    l->lvalid = symtab_get_or_insertl(p->st, scannerTok(p->s).pos, scannerTok(p->s).l).k;
    SG_WRITE(2, "lvalid = ");
    symtabPrintSymK(2, p->st, l->lvalid);
    SG_WRITE(2, "\n");
    l->ln = scannerTok(p->s).ln;
    
    scannerAdvance(p->s);
    if(!parserMatch(p, TOKEN_dot))
        // no feature
        return l;
    
    // feature
    l->type = PAST_NODE_TYPE_FACCESS;
    SG_WRITE(2, "It's a feature\n");
    if(scannerTok(p->s).tok != TOKEN_id) {
        parserErr(p, "--Expected feature id--\n");
    }
    l->a = parseLval(p);
    if(l->a) {
        l->owna = 1;
    } else {
        parserErr(p, "--Expected feature to follow '.'--\n");
        destroyParserExp(l);
        return NULL;
    }
    SG_WRITE(2, "Returning\n");
    
    return l;
}

singleImport* parseSingleImport(parser* p) {
    parserExp* e;
    singleImport* s;
    // get the import exp
    e = parseImportChain(p);
    //AN(s->exp, "Failed to parse single import exp");
    if(!e)
        return NULL;
    s = createSingleImport();
    s->exp = e;
    // default value for symbol
    s->sym = getTerminalField(s->exp);
    if(parserMatchIdC(p, "as")) {
        // overwrite symbol of user-specified
        s->sexp = parseSymbol(p);
        AN(s->sexp, "No symbol");
        AT(s->sexp->type == PAST_NODE_TYPE_SYMBOL, "Expected import as symbol");
        s->sym = exprGetSymbol(s->sexp);
    }
    return s;
}

/// parseImportStmt
parserExp* parseImportStmt(parser* p) {
    parserExp* e;
    singleImport* s;
    importStmt* h = createImportStmt();
    SG_WRITE(2, "*Parsing import statement*\n");
    goto firstpass;
    while(1) {
        if(parserMatch(p, TOKEN_comma))
            AN(0, "Expected comma separating single imports");
        firstpass:
        s = parseSingleImport(p);
        if(!s)
            break;
        importStmtPushSingle(h,s);
    }
    e = createParserExp();
    e->type = PAST_NODE_TYPE_IMPORT;
    e->v.imp = h;
    return e;
}

/// parseNetworkRule
parserExp* parseNetworkRxn(parser* p) {
    parserExp *r, *q, *rxn;
    
    r = parseE(p);
    AN(r);
    
    if(!parserMatch(p, TOKEN_arrow))
        AN(0, "Expected arrow in reaction");
    
    q = parseE(p);
    AN(q);
    
    rxn = createParserExp();
    rxn->type = PAST_NODE_TYPE_RXN;
    
    rxn->a = r;
    rxn->owna = 1;
    
    rxn->b = q;
    rxn->ownb = 1;
    
    return rxn;
}

/// parseNetworkRule
parserExp* parseNetworkRule(parser* p) {
    parserExp *rxn, *rate, *rule;
    
    rxn = parseNetworkRxn(p);
    AN(rxn);
    
    if(!parserMatch(p, TOKEN_comma))
        AN(0, "Expected arrow in reaction");
    
    rate = parseE(p);
    AN(rate);
    
    rule = createParserExp();
    rule->type = PAST_NODE_TYPE_RXN_RULE;
    
    rule->a = rxn;
    rule->owna = 1;
    
    rule->b = rate;
    rule->ownb = 1;
    
    return rule;
}

/// parseNetworkDef
parserExp* parseNetworkDef(parser* p) {
    int supp;
    parserExp *e, *a, *b=NULL, *r;
    
    if(!parserMatch(p, TOKEN_lparen)) {
        parserErr(p, "Expected '(' after 'network'\n");
        return NULL;
    }
    
    supp = scannerSuppNL(p->s, 1);
    
    e = createParserExp();
    e->type = PAST_NODE_TYPE_NETWORK;
    
    while(!parserMatch(p, TOKEN_rparen)) {
        r = parseNetworkRule(p);
        a = createParserExp();
        a->type = PAST_NODE_TYPE_RXN_RULE_LINK;
        a->a = r;
        a->owna = 1;
        
        if(b) {
            b->b = a;
            b->ownb = 1;
            b = a;
        } else
            e->a = b = a;
        if(!parserMatch(p, TOKEN_semicol))
            AT(scannerTok(p->s).tok == TOKEN_rparen, "Expected semicolon or closing parenthesis");
    }
    
    scannerSuppNL(p->s, supp);
    return e;
}

/// parseFunDef
functionDef* parseFunDef(parser* p) {
    block_info block;
    functionDef* f=createFunctionDef();
    SG_WRITE(2, "*Parsing function def*\n");
    //function id
    if(scannerTok(p->s).tok != TOKEN_id) {
        AN(0);
        return NULL;
    }
    //save the id
    f->id = symtab_get_or_insertl(p->st, scannerTok(p->s).pos, scannerTok(p->s).l).k;
    scannerAdvance(p->s);
    if(!parserMatch(p, TOKEN_lparen)) {
        parserErr(p, "Expected parameter list to follow function definition\n");
        destroyFunctionDef(f);
        return NULL;
    }
    f->pl = parseParamList(p);
    
    //parse block open
    //SG_WRITE(2, "Parsing open block\n");
    block = scannerOpenBlock(p->s);
    //SG_WRITE(2, "Open block type: ");
    //sg_writeUInt(2, block.t);
    //SG_WRITE(2, "\n");
    if(block.t == BLOCK_DELIM_INVALID) {
        parserErr(p, "Expected beginning of a block after function def\n");
        destroyFunctionDef(f);
        return NULL;
    } /*else {
        SG_WRITE(2, "Block type: ");
        sg_writeInt(2, block.t);
        SG_WRITE(2, "\n");
    }*/
    
    // parse body
    f->b = parseBasicBody(p, block);
    AN(f->b, "No body");
    
    
    //parse block close
    discardNewline(p);
    SG_WRITE(2, "Parsing block close\n");
    if(scannerCloseBlock(p->s, block) ) {
        parserErr(p, "Expected end of block\n");
        destroyFunctionDef(f);
        return NULL;
    }
    return f;
}

/// parseParamList
paramList* parseParamList(parser* p) {
    paramList* l;
    if(parserMatch(p, TOKEN_rparen))
        return NULL;
    l = createParamList();
    do {
        paramListPush(l, parseParam(p));
    } while(!parserMatch(p, TOKEN_rparen) && !scannerEOI(p->s));
    return l;
}

/// parseParam
paramListElt parseParam(parser* p) {
    paramListElt e;
    if(scannerTok(p->s).tok != TOKEN_id) {
        parserErr(p, "--Expected id--\n");
        scannerAdvance(p->s);
        return e;
    }
    // reference
    if(parserMatchIdC(p, "ref"))
        e.ref = 1;
    else
        e.ref = 0;
    
    // id
    e.sym = symtab_get_or_insertl(p->st, scannerTok(p->s).pos, scannerTok(p->s).l);
    scannerAdvance(p->s);
    
    return e;
}

/// parseBasicBody
parserExp* parseBasicBody(parser* p, block_info blok) {
    parserExp* b=NULL;
    SG_WRITE(2, "*Parsing basic body*\n");
    while(!scannerEOI(p->s) || p->intr) {
        parserExp* e;
        if(scannerShouldCloseBlock(p->s, blok)) {
            SG_WRITE(2, "Closing basic body\n");
            return b;
        }
        e = parseExpr(p);
        if(e) {
            if(!b)
                b = createParserExp();
            else {
                b->b = createParserExp();
                b = b->b;
            }
            b->type = PAST_NODE_TYPE_BBLOCK_LINK;
            b->a = e;
            b->owna = 1;
        }
    }
    return b;
}

/// parseExpr
parserExp* parseExpr(parser* p) {
    parserExp* e;
    SG_WRITE(2, "*Parsing expression*\n");
    
    if(parserMatchIdC(p, "import")) {
        return parseImportStmt(p);
    } else if(parserMatchIdC(p, "network")) {
        return parseNetworkDef(p);
    }
    
    e = parseFactor(p);
    
    while(1) {
        if(parserMatch(p, TOKEN_lparen)) {
            SG_WRITE(2, "CALL\n");
            // call
            e = parseCall(p, e);
            continue;
        }else if(parserMatch(p, TOKEN_nl)) {
            // newline terminates expression
            SG_WRITE(2, "Newline terminates expression\n");
            return e;
        } else if(parserMatch(p, TOKEN_eq)) {
            SG_WRITE(2, "EQ\n");
            // assignment
            parserExp* a = createParserExp();
            //SG_WRITE(2, "TOKEN_eq\n");
            a->type = PAST_NODE_TYPE_ASSN;
            a->a = e;
            a->owna = 1;
            
            a->b = parseExpr(p);
            if(!a->b) {
                parserErr(p, "--Expected rvalue to follow '='--\n");
            }
            a->ownb = 1;
            
//             if(!parserMatch(p, TOKEN_nl)) {
//                 if(scannerTok(p->s).tok == SCANNER_EOI)
//                     return a;
//                 else {
//                     parserErr(p, "--Expected newline at end of statement--\n");
//                     AN(0, "--Expected newline at end of statement--");
//                     destroyParserExp(a);
//                     return NULL;
//                 }
//             }
            
            return a;
        } else {
            SG_WRITE(2, "parseExpr: done\n");
            return e;
        }
    }
    
    AN(0, "Can't touch this");
    return NULL;
}

/// parseFactor
parserExp* parseFactor(parser* p) {
    parserExp* e;
    
    // try integral
    if(scannerTok(p->s).tok == TOKEN_integral) {
        e = parseIntegral(p);
    } else if(scannerTok(p->s).tok == TOKEN_strsng || scannerTok(p->s).tok == TOKEN_strdbl) {
        // try string
        e = parseString(p);
    } else
        // try lvalue
        e = parseLval(p); //lvalue
    
    if(!e) {
        AN(0, "Failed to parse lvalue");
        destroyParserExp(e);
        return NULL;
    }
    
    while(1) {
        if(scannerTok(p->s).tok == TOKEN_dot) {
            SG_WRITE(2, "FA\n");
            // feature
            e = parseFeature(p, e);
            continue;
        } else {
            break;
        }
    }
    
    return e;
}

/// parseFeature
parserExp* parseFeature(parser* p, parserExp* lhs) {
    parserExp* x;
    
    if(!parserMatch(p, TOKEN_dot)) {
        AN(0, "Expected dot");
        return NULL;
    }
    
    //id
    if(scannerTok(p->s).tok != TOKEN_id) {
        parserErr(p, "--Expected lvalue symbol--\n");
        return NULL;
    }
    
    x = createParserExp();
    x->type = PAST_NODE_TYPE_FACCESS;
    
    x->a = lhs;
    x->owna = 1;
    
    x->lvalid = symtab_get_or_insertl(p->st, scannerTok(p->s).pos, scannerTok(p->s).l).k;
    scannerAdvance(p->s);
        SG_WRITE(2, "lvalid = ");
        symtabPrintSymK(2, p->st, x->lvalid);
        SG_WRITE(2, "\n");
    
    x->ln = scannerTok(p->s).ln;
    
    return x;
}

/// parseCall
parserExp* parseCall(parser* p, parserExp* e) {
    // call
    parserExp *callexp=createParserExp(), *x=NULL, *y;
    callexp->type = PAST_NODE_TYPE_CALL;
    callexp->a = e;
    
    while(scannerTok(p->s).tok != TOKEN_rparen) {
        y = parseExpr(p);
        if(y) {
            SG_WRITE(2, "Got arg\n");
            parserExp *z=createParserExp();
            z->type = PAST_NODE_TYPE_RVAL_LINK;
            z->a = y;
            z->owna = 1;
            
            if(x) {
                x->b = z;
                x->ownb = 1;
                x = z;
            } else {
                callexp->b = x = z;
                callexp->ownb = 1;
            }
            
            parserMatch(p, TOKEN_comma);
        } else {
            SG_WRITE(2, "Did not get arg\n");
            break;
        }
    }
    
    if(!parserMatch(p, TOKEN_rparen)) {
        parserErr(p, "--Expected ')'--\n");
        AN(0, "--Expected ')'--");
        destroyParserExp(e);
        return NULL;
    }
    
    return callexp;
}

/// parseLval
parserExp* parseLval(parser* p) {
    SG_WRITE(2, "parseLval\n");
    parserExp* l;
    //id
    if(scannerTok(p->s).tok != TOKEN_id) {
        parserErr(p, "--Expected lvalue symbol--\n");
        return NULL;
    }
    l = createParserExp();
    l->type = PAST_NODE_TYPE_SYMBOL;
    l->lvalid = symtab_get_or_insertl(p->st, scannerTok(p->s).pos, scannerTok(p->s).l).k;
    SG_WRITE(2, "lvalid = ");
    symtabPrintSymK(2, p->st, l->lvalid);
    SG_WRITE(2, "\n");
    l->ln = scannerTok(p->s).ln;
    
    scannerAdvance(p->s);
//     if(!parserMatch(p, TOKEN_dot))
//         // no feature
//         return l;
    
    // feature
//     l->type = PAST_NODE_TYPE_FACCESS;
//     SG_WRITE(2, "It's a feature\n");
//     if(scannerTok(p->s).tok != TOKEN_id) {
//         parserErr(p, "--Expected feature id--\n");
//     }
//     l->a = parseLval(p);
//     if(l->a) {
//         l->owna = 1;
//     } else {
//         parserErr(p, "--Expected feature to follow '.'--\n");
//         destroyParserExp(l);
//         return NULL;
//     }
//     SG_WRITE(2, "Returning\n");
    
    return l;
}

/// parseE
parserExp* parseE(parser* p) {
    parserExp *t, *ep;
    USING_EXPANSION("E -> TE'\n");
    t = parseT(p);
    ep = parseEp(p);
    
    if(ep) {
        AZ(ep->a, "Replacement not possible");
        ep->a = t;
        return ep;
    } else
        return t;
}

/// parseEp
parserExp* parseEp(parser* p) {
    parserExp *ep, *epp, *t;
    switch(scannerTok(p->s).tok) {
        case TOKEN_plus:
            USING_EXPANSION("E' -> +TE'\n");
            scannerAdvance(p->s);
            
            ep = createParserExp();
            ep->type = PAST_NODE_TYPE_ADD;
            t = parseT(p);
            epp = parseEp(p);
            if(epp) {
                epp->a = t;
                ep->b = epp;
            } else
                ep->b = t;
            return ep;
        case TOKEN_dash:
            USING_EXPANSION("E' -> -TE'\n");
            scannerAdvance(p->s);
            
            ep = createParserExp();
            ep->type = PAST_NODE_TYPE_SUB;
            t = parseT(p);
            epp = parseEp(p);
            if(epp) {
                epp->a = t;
                ep->b = epp;
            } else
                ep->b = t;
            return ep;
        default:
            return NULL;
    }
}

/// parseT
parserExp* parseT(parser* p) {
    parserExp *f, *tp;
    USING_EXPANSION("T -> FT'\n");
    f = parseF(p);
    tp = parseTp(p);
    
    if(tp) {
        AZ(tp->a, "Replacement not possible");
        tp->a = f;
        return tp;
    } else
        return f;
}

/// parseTp
parserExp* parseTp(parser* p) {
    parserExp *tp, *tpp, *f;
    switch(scannerTok(p->s).tok) {
        case TOKEN_star:
            USING_EXPANSION("T' -> *FT'\n");
            scannerAdvance(p->s);
            
            tp = createParserExp();
            tp->type = PAST_NODE_TYPE_MUL;
            f = parseF(p);
            tpp = parseTp(p);
            if(tpp) {
                tpp->a = f;
                tp->b = tpp;
            } else
                tp->b = f;
            return tp;
        case TOKEN_slash:
            USING_EXPANSION("T' -> /FT'\n");
            scannerAdvance(p->s);
            
            tp = createParserExp();
            tp->type = PAST_NODE_TYPE_DIV;
            f = parseF(p);
            tpp = parseTp(p);
            if(tpp) {
                tpp->a = f;
                tp->b = tpp;
            } else
                tp->b = f;
            return tp;
        default:
            return NULL;
    }
}

/// parseF
parserExp* parseF(parser* p) {
    parserExp *b, *fp;
    USING_EXPANSION("F -> BF'\n");
    b = parseB(p);
    fp = parseFp(p);
    
    if(fp) {
        AZ(fp->a, "Replacement not possible");
        fp->a = b;
        return fp;
    } else
        return b;
}

/// parseFp
parserExp* parseFp(parser* p) {
    parserExp *fp, *fpp, *b;
    switch(scannerTok(p->s).tok) {
        case TOKEN_carrot:
            USING_EXPANSION("F' -> ^BF'\n");
            scannerAdvance(p->s);
            
            fp = createParserExp();
            fp->type = PAST_NODE_TYPE_MUL;
            b = parseF(p);
            fpp = parseTp(p);
            if(fpp) {
                fpp->a = b;
                fp->b = fpp;
            } else
                fp->b = b;
            return fp;
        default:
            return NULL;
    }
}

/// parseB
parserExp* parseB(parser* p) {
    parserExp *e, *neg;
    switch(scannerTok(p->s).tok) {
        case TOKEN_lparen:
            USING_EXPANSION("B -> (E)\n");
            scannerAdvance(p->s);
            
            e = parseE(p);
            
            if(!parserMatch(p, TOKEN_rparen))
                AN(0, "Expected closing parenthesis");
            
            return e;
        case TOKEN_tilde:
            scannerAdvance(p->s);
            neg = createParserExp();
            if(scannerTok(p->s).tok == TOKEN_lparen) {
                USING_EXPANSION("B -> ~(E)\n");
                scannerAdvance(p->s);
                
                neg->a = parseE(p);
                neg->owna = 1;
                
                if(!parserMatch(p, TOKEN_rparen))
                    AN(0, "Expected closing parenthesis");
                
                return neg;
            } else {
                USING_EXPANSION("B -> ~expr\n");
                
                neg->a = parseExpr(p);
                neg->owna = 1;
                return neg;
            }
        default:
            USING_EXPANSION("B -> expr\n");
            return parseExpr(p);
    }
}

/// parseSymbol
parserExp* parseSymbol(parser* p) {
    parserExp* l;
    //id
    if(scannerTok(p->s).tok != TOKEN_id) {
        return NULL;
    }
    l = createParserExp();
    l->type = PAST_NODE_TYPE_SYMBOL;
    l->lvalid = symtab_get_or_insertl(p->st, scannerTok(p->s).pos, scannerTok(p->s).l).k;
    SG_WRITE(2, "lvalid = ");
    symtabPrintSymK(2, p->st, l->lvalid);
    SG_WRITE(2, "\n");
    l->ln = scannerTok(p->s).ln;
    
    scannerAdvance(p->s);
    
    return l;
}

/// parseLval
parserExp* parseIntegral(parser* p) {
    parserExp* e;
    if(scannerTok(p->s).tok != TOKEN_integral) {
        parserErr(p, "--Expected integral constant--\n");
        return NULL;
    }
    e = createParserExp();
    e->type = PAST_NODE_TYPE_UINT;
    e->ln = scannerTok(p->s).ln;
    e->v.u = scannerIntFromTok(scannerTok(p->s));
    scannerAdvance(p->s);
    return e;
}

/// parseString
parserExp* parseString(parser* p) {
    parserExp* e;
    if(scannerTok(p->s).tok != TOKEN_strsng && scannerTok(p->s).tok != TOKEN_strdbl) {
        parserErr(p, "--Expected string literal--\n");
        return NULL;
    }
    e = createParserExp();
    e->type = PAST_NODE_TYPE_STR;
    e->ln = scannerTok(p->s).ln;
    e->v.str.w = scannerTok(p->s).pos;
    e->v.str.l = scannerTok(p->s).l;
    scannerAdvance(p->s);
    return e;
}

/// parseRval
parserExp* parseRval(parser* p) {
    // try id
    if(scannerTok(p->s).tok == TOKEN_id) {
        parserExp* r = NULL;
        r = createParserExp();
        r->type = PAST_NODE_TYPE_SYMBOL;
        r->lvalid = symtab_get_or_insertl(p->st, scannerTok(p->s).pos, scannerTok(p->s).l).k;
        SG_WRITE(2, "lvalid = ");
        symtabPrintSymK(2, p->st, r->lvalid);
        SG_WRITE(2, "\n");
        r->ln = scannerTok(p->s).ln;
        
        scannerAdvance(p->s);
        if(parserMatch(p, TOKEN_dot)) {
            // feature
            r->type = PAST_NODE_TYPE_FACCESS;
            if(scannerTok(p->s).tok != TOKEN_id) {
                parserErr(p, "--Expected feature id--\n");
            }
            r->a = parseLval(p);
        } else if(parserMatch(p, TOKEN_lparen)) {
            AN(0);
        }
        
        return r;
    } else if(scannerTok(p->s).tok == TOKEN_integral) { // try integral
        // parse integral
        return parseIntegral(p);
    } else if(scannerTok(p->s).tok == TOKEN_strsng || scannerTok(p->s).tok == TOKEN_strdbl) { // try integral
        // parse integral
        return parseString(p);
    } else {
        //didn't work
        parserErr(p, "--Invalid rvalue--\n");
        return NULL;
    }
}
